package com.skyyan.netty.jjf.protocol;

import com.skyyan.netty.jjf.util.BcdUtil;
import io.netty.buffer.ByteBuf;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 报文抽象基类，定义所有报文的通用结构和行为
 * 基于JJF(豫)360-2023规范的帧结构定义
 *
 * 支持两种地址域格式：
 * 1. 标准9字节地址域：A1(3字节BCD) + A2(3字节BCD) + A3(3字节BIN)--设备序列号
 * 2. 扩展20字节地址域：设备注册号(16字节) + 充值管理机序号(4字节)
 * @author skyyan
 */
public abstract class Message {

    // --- 报文头 ---
    private byte control; // 控制域C
    private byte[] address; // 地址域A (9字节或20字节)
    private byte afn;     // 应用层功能码 AFN

    // --- 用户数据 ---
    private byte[] userData; // 用户数据 低位在前 高位在后

    /**
     * 造函数
     * @param control 控制域
     * @param address 地址域 (9字节或20字节)
     * @param afn 应用层功能码
     * @param userData 用户数据
     */
//    public Message(byte control, byte[] address, byte afn, byte[] userData) {
//        if (address == null || (address.length != 9 && address.length != 20)) {
//            throw new IllegalArgumentException("地址域必须为9字节或20字节，实际长度: " +
//                                             (address != null ? address.length : 0));
//        }
//        this.control = control;
//        this.address = address.clone(); // 防御性拷贝
//        this.afn = afn;
//        this.userData = userData != null ? userData.clone() : new byte[0];
//    }
    public Message(byte control, byte[] address, byte afn, byte[] userData) {
        // 如果 address 不为 null，则检查长度是否为 9 或 20
        if (address != null) {
            System.out.println("address长度 = " + address.length);
            // 修正：使用 &&，表示“既不是9，也不是20”时才报错
            if (address.length != 9 && address.length != 19 && address.length != 20) {
                throw new IllegalArgumentException(
                        "地址域必须为 null，或长度为 9 或 20 字节，实际长度: " + address.length
                );
            }
        }
        this.control = control;
        this.address = address != null ? address.clone() : null; // 若 null 则保留 null
        this.afn = afn;
        this.userData = userData != null ? userData.clone() : new byte[0];
    }
    /**
     * 将报文对象的核心数据（除帧头、长度、CRC和帧尾）编码到ByteBuf中
     * @param out Netty的ByteBuf
     */
    public void encodeBody(ByteBuf out) {
        out.writeByte(control);
        if (address != null&& address.length > 0) {
            out.writeBytes(address);
        }
        out.writeByte(afn);
        if (userData != null && userData.length > 0) {
            out.writeBytes(userData);
        }
    }

    /**
     * 获取用户数据区的长度（控制域 + 地址域 + AFN + 用户数据）
     * @return 长度
     */
    public int getUserDataLength() {
        return FrameConstants.CONTROL_FIELD_LENGTH +
                (address != null ? address.length : 0) +
                FrameConstants.AFN_FIELD_LENGTH +
                (userData != null ? userData.length : 0);
    }

    /**
     * 创建标准9字节地址域
     * @param areaCode 行政区划码（6位数字，如"410122"）
     * @param villageCode 镇村编码（6位数字，如"102201"）
     * @param stationId 测站编码（整数，如1）
     * @return 9字节地址域
     */
    public static byte[] createStandardAddress(String areaCode, String villageCode, int stationId) {
        byte[] address = new byte[9];

        try {
            // A1: 行政区划码 (3字节BCD)
            byte[] a1 = BcdUtil.stringToBcd(areaCode, 3);
            System.arraycopy(a1, 0, address, 0, 3);

            // A2: 镇村编码 (3字节BCD)
            byte[] a2 = BcdUtil.stringToBcd(villageCode, 3);
            System.arraycopy(a2, 0, address, 3, 3);

            // A3: 测站编码 (3字节BIN，小端字节序)
            ByteBuffer.wrap(address, 6, 3).order(ByteOrder.LITTLE_ENDIAN)
                    .put((byte)(stationId & 0xFF))
                    .put((byte)((stationId >> 8) & 0xFF))
                    .put((byte)((stationId >> 16) & 0xFF));

        } catch (Exception e) {
            throw new IllegalArgumentException("创建地址域失败: " + e.getMessage(), e);
        }

        return address;
    }

    /**
     * 从标准9字节地址域中提取行政区划码
     * @param address 9字节地址域
     * @return 行政区划码字符串
     */
    public static String extractAreaCode(byte[] address) {
        if (address == null || address.length < 3) {
            return "000000";
        }

        try {
            byte[] a1 = new byte[3];
            System.arraycopy(address, 0, a1, 0, 3);
            return BcdUtil.bcdToString(a1);
        } catch (Exception e) {
            return "000000";
        }
    }

    /**
     * 从标准9字节地址域中提取镇村编码
     * @param address 9字节地址域
     * @return 镇村编码字符串
     */
    public static String extractVillageCode(byte[] address) {
        if (address == null || address.length < 6) {
            return "000000";
        }

        try {
            byte[] a2 = new byte[3];
            System.arraycopy(address, 3, a2, 0, 3);
            return BcdUtil.bcdToString(a2);
        } catch (Exception e) {
            return "000000";
        }
    }

    /**
     * 从标准9字节地址域中提取测站编码
     * @param address 9字节地址域
     * @return 测站编码整数
     */
    public static int extractStationId(byte[] address) {
        if (address == null || address.length < 9) {
            return 0;
        }

        try {
            // A3: 3字节BIN，小端字节序
            int stationId = 0;
            stationId |= (address[6] & 0xFF);
            stationId |= ((address[7] & 0xFF) << 8);
            stationId |= ((address[8] & 0xFF) << 16);
            return stationId;
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 获取地址域的字符串表示（用于调试和日志）
     * @return 地址域字符串
     */
    public String getAddressString() {
        if(address==null){
            return "";
        }
        if (address.length == 9) {
            // 标准9字节地址域
            String areaCode = extractAreaCode(address);
            String villageCode = extractVillageCode(address);
            int stationId = extractStationId(address);
            return String.format("区划:%s,村镇:%s,站点:%d", areaCode, villageCode, stationId);
        } else if (address.length == 20) {
            // 扩展20字节地址域（设备注册号16字节 + 充值管理机序号4字节）
            StringBuilder sb = new StringBuilder();
            sb.append("设备ID:");
            for (int i = 0; i < 16 && i < address.length; i++) {
                if (address[i] != 0) {
                    sb.append((char)address[i]);
                }
            }
            if (address.length >= 20) {
                int managerId = ByteBuffer.wrap(address, 16, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
                sb.append(",管理机:").append(managerId);
            }
            return sb.toString();
        } else {
            // 其他长度的地址域，以十六进制显示
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < address.length; i++) {
                if (i > 0) sb.append(" ");
                sb.append(String.format("%02X", address[i] & 0xFF));
            }
            return "地址[" + address.length + "]:" + sb.toString();
        }
    }

    /**
     * 验证地址域格式是否正确
     * @param address 地址域
     * @return true表示格式正确
     */
    public static boolean isValidAddress(byte[] address) {
        if (address == null) {
            return false;
        }

        if (address.length == 9) {
            // 验证标准9字节地址域的BCD部分
            try {
                byte[] a1 = new byte[3];
                byte[] a2 = new byte[3];
                System.arraycopy(address, 0, a1, 0, 3);
                System.arraycopy(address, 3, a2, 0, 3);

                return BcdUtil.isValidBcd(a1) && BcdUtil.isValidBcd(a2);
            } catch (Exception e) {
                return false;
            }
        } else if (address.length == 20) {
            // 扩展20字节地址域，暂时认为都有效
            return true;
        } else {
            // 其他长度暂时认为无效
            return false;
        }
    }

    // --- Getters and Setters ---
    public byte getControl() {
        return control;
    }

    public byte[] getAddress() {
        return address != null ? address.clone() : null; // 防御性拷贝
    }

    public byte getAfn() {
        return afn;
    }

    public byte[] getUserData() {
        return userData != null ? userData.clone() : new byte[0]; // 防御性拷贝
    }

    public void setUserData(byte[] userData) {
        this.userData = userData != null ? userData.clone() : new byte[0];
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.getClass().getSimpleName()).append("{");

        // control 域：基本类型，不可能 null，安全
        sb.append("control=").append(String.format("0x%02X", control & 0xFF)).append(", ");

        // address 域：可能为 null
        if (address == null) {
            sb.append("address=null");
        } else {
            sb.append("addressLen=").append(address.length).append(", ");
            sb.append("address=");
            for (int i = 0; i < address.length; i++) {
                if (i > 0) sb.append(" ");
                sb.append(String.format("%02X", address[i] & 0xFF));
            }
        }

        sb.append(", "); // 分隔 address 和 afn

        // afn 域：基本类型，安全
        sb.append("afn=").append(String.format("0x%02X", afn & 0xFF)).append(", ");

        // userData 域：可能为 null 或空
        if (userData == null) {
            sb.append("userData=null");
        } else if (userData.length == 0) {
            sb.append("userDataLen=0, userData=<empty>");
        } else {
            sb.append("userDataLen=").append(userData.length).append(", ");
            sb.append("userData=");
            for (int i = 0; i < userData.length; i++) {
                if (i > 0) sb.append(" ");
                sb.append(String.format("%02X", userData[i] & 0xFF));
            }
        }

        sb.append('}');
        return sb.toString();
    }

}
